package com.qfx.modules.test.controller.executorService;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.StopWatch;

/**
 * 线程池示例
 *
 */
public class ExecutorSerDemo {
	private static final Logger LOG = LogManager.getLogger();
	
	public static void main(String[] args) {
		ExecutorSerDemo es = new ExecutorSerDemo();
		StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
		es.test01();
//		es.test02();
//		es.test03();
//		es.test04();
		
		stopWatch.stop();
		// 统计用时
		long[] de = formatDurationByMillis(stopWatch.getTotalTimeMillis());
		
		System.out.println("用时:" + de[0] + "天" + de[1] + "小时" + de[2] + "分" + de[3] + "秒" + de[4] + "毫秒");
	}
	
	
	/**
	 * 无参数,且不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
	 * execute(Runnable command):
	 * 	将一个Runnable任务提交给线程池执行。该方法将会在ThreadPoolExecutor内部的阻塞队列中插入任务，等待线程池中的线程执行任务。
	 */
	public void test01(){
		ExecutorSerDemo es = new ExecutorSerDemo();
		
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		for (int i = 0; i < 5; i++) {
			// 使用匿名内部类的方式创建一个实现了Runnable接口的对象,并在run()方法中调用es.hello01()方法
//			executorService.execute(new Runnable() {
//				@Override
//				public void run() {
//					es.hello01();
//				}
//			});
			// 建议使用Lambda表达式的方式,更加简洁易读
			executorService.execute(() -> es.hello01());
		}
		
		executorService.shutdown();
		System.out.print("test01()执行完毕,");
	}
	
	/**
	 * 无参数,接收返回数据(需等待线程执行完毕并继续执行后续业务)
	 */
	public void test02() {
		ExecutorSerDemo es = new ExecutorSerDemo();

		ExecutorService executorService = Executors.newFixedThreadPool(3);
		List<Future<String>> list = new ArrayList<>();
		
		for (int i = 0; i < 5; i++) {
			// executorService.submit可以接收返回结果
			Future<String> submit = executorService.submit(()->es.hello02());
			list.add(submit);
		}
		
		List<String> dataList = new ArrayList<>();
		try {
			// 接收返回数据
			for (Future<String> future : list) {
				String str = future.get();
				dataList.add(str);
			}
		} catch (Exception e) {
			// 如果发生异常则结束所有线程
			for (Future<?> future : list) {
				future.cancel(true);
			}
		}
		
		
		// 关闭线程池
		executorService.shutdown();
		
		for (int i = 0; i < dataList.size(); i++) {
			System.err.println("接收到的数据:" + dataList.get(i));
		}
		System.out.print("test02()执行完毕,");
	}
	
	/**
	 * 有参数,但不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
	 */
	public void test03() {
		List<String> nameList = new ArrayList<>();
		nameList.add("小橙");
		nameList.add("小红");
		nameList.add("小青");
		nameList.add("小白");
		nameList.add("小紫");
		
		ExecutorSerDemo es = new ExecutorSerDemo();
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		
		for (int i = 0; i < nameList.size(); i++) {
			// executorService.submit可以接收返回结果
			int num = i;
			executorService.execute(()->es.hello03(nameList.get(num)));
		}
		
		// 关闭线程池
		executorService.shutdown();
		System.out.print("test03()执行完毕,");
	}
	
	/**
	 * 有参数,接收返回数据,等待线程执行完毕再继续执行后续业务
	 */
	public void test04() {
		List<String> nameList = new ArrayList<>();
		nameList.add("张三");
		nameList.add("李四");
		nameList.add("王五");
		nameList.add("赵六");
		nameList.add("林七");
		
		ExecutorSerDemo es = new ExecutorSerDemo();

		ExecutorService executorService = Executors.newFixedThreadPool(3);
		List<Future<String>> list = new ArrayList<>();
		
		for (int i = 0; i < nameList.size(); i++) {
			// executorService.submit可以接收返回结果
			int num = i;
			Future<String> submit = executorService.submit(()->es.hello04(nameList.get(num)));
			list.add(submit);
		}
		
		List<String> dataList = new ArrayList<>();
		try {
			// 接收返回数据
			for (Future<String> future : list) {
				String str = future.get();
				dataList.add(str);
			}
		} catch (Exception e) {
			for (Future<?> future : list) {
				future.cancel(true);
			}
		}
		
		
		// 关闭线程池
		executorService.shutdown();
		
		for (int i = 0; i < dataList.size(); i++) {
			System.err.println(dataList.get(i));
		}
		
		System.out.print("test04()执行完毕,");
	}
	
	// ------------------- private method -------------------
	/**
	 * 无参数，无返回值
	 */
	private void hello01() {
		try {
			Thread.sleep(5000);
			LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello01()完毕,无参数无返回数据,异步执行");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 无参数，有返回值
	 */
	private String hello02() {
		try {
			Thread.sleep(3000);
			LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello02()完毕,无参数有返回数据,需等待线程执行完毕");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// 返回随意的一串字符串
		return "我返回的是随机字符串:" + UUID.randomUUID().toString();
	}
	
	/**
	 * 有参数，无返回值
	 */
	private void hello03(String name) {
		try {
			Thread.sleep(5000);
			LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello03()完毕,有参数无返回数据,异步执行");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 有参数，有返回值
	 */
	private String hello04(String name) {
		try {
			Thread.sleep(5000);
			LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello04()完毕,有参数有返回数据,需等待线程执行完毕");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "我返回的是" + name + "的数据";
	}
	
	/**
	 * <h5>功能:根据毫秒数来格式化持续时间</h5>
	 * 
	 * @param millis 毫秒数
	 * @return long[] 返回值为：{天, 时, 分, 秒, 毫秒}
	 */
	private static long[] formatDurationByMillis(long millis) {
		long day = TimeUnit.MILLISECONDS.toDays(millis);
		long hour = TimeUnit.MILLISECONDS.toHours(millis) % 24;
		long minute = TimeUnit.MILLISECONDS.toMinutes(millis) % 60;
		long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % 60;
		millis = millis % 1000;

		long[] times = { day, hour, minute, seconds, millis };
		return times;
	}
}
